package com.threeti.mecool.framework.domain;

import static com.threeti.mecool.framework.util.OrmUtils.unwrapOrmProxy;

import java.io.Serializable;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 实体的抽象实现<p/>
 *
 * @author Jay Meng
 */
@MappedSuperclass
@SuppressWarnings("serial")
public abstract class AbstractDomainEntity<ID extends Serializable> implements DomainEntity<ID> {
  private static final Logger logger = LoggerFactory.getLogger(AbstractDomainEntity.class);

  @Override

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  public abstract ID getId();

  @Override
  public abstract void setId(ID id);

  @Override
  public final int hashCode() {
    if ((this.getId() == null)) {
      logger.warn("实体未提供明确的标识，将使用默认的hashCode");
      return super.hashCode();
    }
    return this.getId().hashCode();
  }

  /**
   *
   * @param other 另一实体.
   * @return true 如果两个实体相等(即它们的标识(标识属性)相同)
   *
   * @throws InvalidEntityCompareException 目前还不支持transient和non-transient(persistent or detached)entity之间的比较
   *
   */
  @Override
  @SuppressWarnings("unchecked")
  public final boolean equals(final Object other) {
    if (other == null) return false;
    if (this == other) return true;
    if (unwrapOrmProxy(this).getClass() != unwrapOrmProxy(other).getClass()) return false;

    return sameAs((DomainEntity<ID>)other);
  }

  protected boolean sameAs(final DomainEntity<ID> other) {
    if (other == null) return false;//double check

    ID id = this.getId();
    ID otherId = other.getId();
    
    if ((id != null) && (otherId != null)) {
      return id.equals(otherId);
    }
    
    throw new InvalidEntityCompareException(new UnsupportedOperationException("不支持Transient或身份模糊的Entity间的比较"));
  }

}
